package cn.com.digitalnet.ad.web.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * 使用gzip的压缩格式输出
 * @author qidafang
 */
public class GzipFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        
        ByteArrayOutputStream byteArrayOutputStream4Servlet = new ByteArrayOutputStream();
        BufferedServletOutputStream bufferedServletOutputStream = new BufferedServletOutputStream(byteArrayOutputStream4Servlet);
        PrintWriter printWriter =  new PrintWriter(new OutputStreamWriter(bufferedServletOutputStream,response.getCharacterEncoding()));
        
        HttpServletResponse wrapper = new GzipResponseWrapper(response,bufferedServletOutputStream,printWriter);
        chain.doFilter(request, wrapper);

    	bufferedServletOutputStream.close();
        printWriter.close();
            
        //此时数据已经封装到了bout中
        byte data[] = byteArrayOutputStream4Servlet.toByteArray(); //获得写出去的数据,截留下来, 不管调用是哪个流,最终都会被写到bout中去,这时要注意,filter要捕获servlet的输出,并把servlet输出写到buffer,然后,把数据再写给浏览器.
        if(data.length > 0){
	        ByteArrayOutputStream byteArrayOutputStream4Gzip = new ByteArrayOutputStream();  //再定义一个低层流,此类实现了一个输出流，其中的数据被写入一个 byte 数组。
	
	        GZIPOutputStream gout = new GZIPOutputStream(byteArrayOutputStream4Gzip);   //把获得的数据压缩之后先不写出去,先写到bout2流
	        gout.write(data);     //将数据写到一个流中
	        gout.close();
	        byte gzip[] = byteArrayOutputStream4Gzip.toByteArray();  //获得写完了之后的压缩数据
	        
	        response.setHeader("content-encoding", "gzip");
	        response.setContentLength(gzip.length);
	        
	        try{
	        	//System.out.println("path:"+request.getRequestURI());
	        	//System.out.println("before gzip:"+data.length);
	        	//System.out.println("after gzip:"+gzip.length);
	        	response.getOutputStream().write(gzip);  //最后采用response把压缩后的数据写出去
	        }catch(Throwable t){
	        	t.printStackTrace();
	        	//System.out.println("error::"+request.getRequestURI());
	        	//System.out.println(response.getStatus());
	        }
        }
    }
    
    class BufferedServletOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bout;
        public BufferedServletOutputStream(ByteArrayOutputStream bout){
            this.bout = bout;
        }
        @Override
        public void write(int b) throws IOException {
            this.bout.write(b);
        }
        
    }
    
    class GzipResponseWrapper extends HttpServletResponseWrapper{
    	private ServletOutputStream servletOutputStream;
    	private PrintWriter printWriter;
		public GzipResponseWrapper(HttpServletResponse response,ServletOutputStream servletOutputStream,PrintWriter printWriter){
			super(response);
			this.servletOutputStream = servletOutputStream;
			this.printWriter = printWriter;
		}
		@Override
		public ServletOutputStream getOutputStream() throws IOException {
			return servletOutputStream;
		}
		@Override
		public PrintWriter getWriter() throws IOException {
			return printWriter;
		}
		
    }
    
    public void destroy() {}
    
    public void init(FilterConfig filterConfig) throws ServletException {}

} 